package com.meilingcloud.biobank.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilingcloud.biobank.domain.Source;
import com.meilingcloud.biobank.domain.SourceType;
import com.meilingcloud.biobank.domain.dto.PatientTreatmentInfoDto;
import com.meilingcloud.biobank.domain.dto.SetUpPatientRemindersDto;
import com.meilingcloud.biobank.domain.view.Hzxx;
import com.meilingcloud.biobank.domain.view.Jzxx;
import com.meilingcloud.biobank.domain.view.Yyxx;
import com.meilingcloud.biobank.domain.view.Zdxx;
import com.meilingcloud.biobank.domain.vo.*;
import com.meilingcloud.biobank.mapper.SourceMapper;
import com.meilingcloud.biobank.service.*;
import com.meilingcloud.common.enums.AttachModule;
import com.meilingcloud.common.exception.CustomException;
import com.meilingcloud.common.utils.SecurityUtils;
import com.meilingcloud.system.domain.SysAttach;
import com.meilingcloud.system.service.ISysAttachService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 样本源 Service业务层处理
 *
 * @author chenl
 * @date 2021-02-26
 */
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Service
public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> implements ISourceService {

    private final ISourceTypeService sourceTypeService;
    private final ISysAttachService sysAttachService;

    private final IHzxxService hzxxService;

    private final IYyxxService yyxxService;

    private final IZdxxService zdxxService;

    private final IJzxxService jzxxService;

    private final ISourceUtilService sourceUtilService;

    @Override
    public List<Source> queryList(Source source) {
        LambdaQueryWrapper<Source> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(source.getSourceCode())) {
            lqw.eq(Source::getSourceCode, source.getSourceCode());
        }
        if (source.getSourceTypeId() != null) {
            lqw.eq(Source::getSourceTypeId, source.getSourceTypeId());
        }
        if (StringUtils.isNotBlank(source.getSourceName())) {
            lqw.like(Source::getSourceName, source.getSourceName());
        }
        if (StringUtils.isNotBlank(source.getSourceDesc())) {
            lqw.eq(Source::getSourceDesc, source.getSourceDesc());
        }
        if (StringUtils.isNotBlank(source.getFollowState())) {
            lqw.eq(Source::getFollowState, source.getFollowState());
        }
        if (StringUtils.isNotBlank(source.getVisitReminder())) {
            lqw.eq(Source::getVisitReminder, source.getVisitReminder());
        }
        return this.list(lqw);
    }

    @Override
    public List<Source> queryListWithSourceType(List<Source> sources) {
        if (CollectionUtil.isEmpty(sources)) {
            return sources;
        }
        List<Long> sourceTypeIds = sources.stream().map(Source::getSourceTypeId).collect(Collectors.toList());
        List<SourceType> sourceTypes = sourceTypeService.listByIds(sourceTypeIds);
        List<Source> collect = sources.stream().map(item -> sourceTypes.stream()
                .filter(type -> ObjectUtil.equal(item.getSourceTypeId(), type.getSourceTypeId()))
                .findAny()
                .map(type -> {
                    item.setSourceTypeCode(type.getSourceTypeCode());
                    item.setSourceTypeName(type.getSourceTypeName());
                    return item;
                }).orElse(null)).collect(Collectors.toList());
        return collect;
    }

    @Override
    public Source queryById(Long sourceId) {
        Source source = this.getById(sourceId);
        SysAttach sysAttach = new SysAttach();
        sysAttach.setRelateId(String.valueOf(sourceId));
        sysAttach.setModule(AttachModule.SAMPLE_SOURCE.getCode());
        List<SysAttach> sysAttaches = sysAttachService.queryList(sysAttach);
        source.setAttaches(sysAttaches);
        return source;
    }

    @Override
    public Source queryByCode(String sourceCode) {
        Source source = this.getOne(new LambdaQueryWrapper<Source>().eq(Source::getSourceCode, sourceCode).last("limit 1"));
        if (ObjectUtil.isNotEmpty(source)) {
            SysAttach sysAttach = new SysAttach();
            sysAttach.setRelateId(String.valueOf(source.getSourceId()));
            sysAttach.setModule(AttachModule.SAMPLE_SOURCE.getCode());
            List<SysAttach> sysAttaches = sysAttachService.queryList(sysAttach);
            source.setAttaches(sysAttaches);
        }
        return source;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveSource(Source source) {
        if (source.getFormDataSaveDto() != null) {
            source.setFormData(JSON.toJSONString(source.getFormDataSaveDto().getData()));
            source.setFormDesc(JSON.toJSONString(source.getFormDataSaveDto().getDesc()));
        }
        boolean result = this.save(source);
        // 写入附件表
        List<SysAttach> attaches = source.getAttaches();
        if (CollectionUtil.isNotEmpty(attaches)) {
            List<SysAttach> attachList = attaches.stream().map(item -> {
                item.setRelateId(String.valueOf(source.getSourceId()));
                item.setModule(AttachModule.SAMPLE_SOURCE.getCode());
                item.setCreateBy(SecurityUtils.getUsername());
                return item;
            }).collect(Collectors.toList());
            sysAttachService.saveOrUpdateBatch(attachList);
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateSource(Source source) {
        if (source.getFormDataSaveDto() != null) {
            source.setFormData(JSON.toJSONString(source.getFormDataSaveDto().getData()));
            source.setFormDesc(JSON.toJSONString(source.getFormDataSaveDto().getDesc()));
        }
        boolean result = this.updateById(source);
        // 写入附件表
        List<SysAttach> attaches = source.getAttaches();
        if (CollectionUtil.isNotEmpty(attaches)) {
            List<SysAttach> attachList = attaches.stream().map(item -> {
                item.setRelateId(String.valueOf(source.getSourceId()));
                item.setModule(AttachModule.SAMPLE_SOURCE.getCode());
                item.setCreateBy(SecurityUtils.getUsername());
                return item;
            }).collect(Collectors.toList());
            sysAttachService.saveOrUpdateBatch(attachList);
        }
        return result;
    }

    @Override
    public List<Source> getDetailByCodeOrName(String codeOrName) {
        List<Source> list = this.list(new LambdaQueryWrapper<Source>().like(Source::getSourceName, codeOrName)
                .or().like(Source::getSourceCode, codeOrName).last("limit 20"));
        return queryListWithSourceType(list);
    }

    @Override
    public List<StatisticVo> statisticSource() {
//        List<SourceType> sourceTypes = sourceTypeService.list();
//        if (CollectionUtil.isEmpty(sourceTypes)) {
//            return new ArrayList<>();
//        }
//        List<StatisticVo> collect = sourceTypes.stream().map(item -> {
//            StatisticVo statisticVo = new StatisticVo();
//            int total = this.count(new LambdaQueryWrapper<Source>().eq(Source::getSourceTypeId, item.getSourceTypeId()));
//            statisticVo.setName(item.getSourceTypeName());
//            statisticVo.setValue(total);
//            return statisticVo;
//        }).collect(Collectors.toList());
//        return collect;
        return this.baseMapper.statisticSource();
    }

    @Override
    public String importSource(List<Source> sources, boolean updateSupport) {
        if (CollectionUtil.isEmpty(sources)) {
            throw new CustomException("导入样本源数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        String username = SecurityUtils.getUsername();
        for (Source source : sources) {
            try {
                SourceType sourceType = sourceTypeService.queryByCode(source.getSourceTypeCode());
                if (ObjectUtil.isEmpty(sourceType)) {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、样本源类型编码 " + source.getSourceTypeCode() + " 不存在");
                    continue;
                }
                source.setSourceTypeId(sourceType.getSourceTypeId());
                source.setCreateBy(username);
                boolean result;
                if (updateSupport) {
                    result = this.saveOrUpdate(source);
                } else {
                    result = this.save(source);
                }
                if (result) {
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、样本源编码 " + source.getSourceCode()
                            + "、样本源名称 " + source.getSourceName()
                            + "、样本源类型编码 " + source.getSourceTypeCode()
                            + " 导入成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、样本源编码 " + source.getSourceCode()
                            + "、样本源名称 " + source.getSourceName()
                            + "、样本源类型编码 " + source.getSourceTypeCode()
                            + " 导入失败");
                }
            } catch (Exception e) {
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、样本源编码 " + source.getSourceCode()
                        + "、样本源名称 " + source.getSourceName()
                        + "、样本源类型编码 " + source.getSourceTypeCode()
                        + " 导入失败");
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new CustomException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public Integer statisticSourceCount() {
        return this.count();
    }

    @Override
    public Source getSourceInfoById(Long sourceId) {
        return this.baseMapper.getSourceInfoById(sourceId);
    }

    /**
     * 根据身份证号查询患者信息
     *
     * @param idCard 身份证
     * @return {@link GetPatientInfoVo}
     */
    @Override
    @DS("oracle_1")
    public GetPatientInfoVo getPatientInfoByIdCard(String idCard) {
        LambdaQueryWrapper<Hzxx> lqw = Wrappers.lambdaQuery();
        lqw.eq(Hzxx::getIdCard, idCard);
        List<Hzxx> hzxxs = hzxxService.list(lqw);
        if (hzxxs.size() > 0) {
            GetPatientInfoVo getPatientInfoVo = BeanUtil.copyProperties(hzxxs.get(0), GetPatientInfoVo.class);
            return getPatientInfoVo;
        } else {
            return null;
        }


    }

    /**
     * 根据条件查询患者用药信息
     *
     * @param dto dto
     * @return {@link List}<{@link GetPatientTreatmentInfoVo}>
     */
    @Override
    public List<GetPatientTreatmentInfoVo> getPatientTreatmentInfo(PatientTreatmentInfoDto dto) {

        GetPatientTreatmentInfoVo build = GetPatientTreatmentInfoVo.builder().id("151212").idCard("758865199606081715").visitCardNo("No421").patientName("张三").diagnosisResult("诊断结果")
                .drugsName("药物名称").Dosage("剂量").DrugsUseCycle("药物使用周期").build();
        GetPatientTreatmentInfoVo build1 = GetPatientTreatmentInfoVo.builder().id("1512121").idCard("7588651996060817151").visitCardNo("No4211").patientName("张三1").diagnosisResult("诊断结果")
                .drugsName("药物名称1").Dosage("剂量1").DrugsUseCycle("药物使用周期1").build();

        List<GetPatientTreatmentInfoVo> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            list.add(GetPatientTreatmentInfoVo.builder().id("151212" + i).idCard("758865199606081715").visitCardNo("No421" + i).patientName("张三" + i).diagnosisResult("诊断结果")
                    .drugsName("药物名称").Dosage("剂量").DrugsUseCycle("药物使用周期").build());
        }

        list.add(build);
        list.add(build1);
        return list;
    }


    /**
     * 设置患者提醒
     *
     * @param dto dto
     * @return int
     */
    @Override
    public int SetUpPatientReminders(SetUpPatientRemindersDto dto) {
        if (BeanUtil.isEmpty(dto) || dto.getIds().isEmpty() || dto.getIds().contains(null) || dto.getIds().contains("")) {
            return 0;
        }
        ArrayList<Source> sources = new ArrayList<>();
        dto.getIds().forEach(T -> {
            Source source = new Source();
            source.setSourceId(Long.valueOf(T));
            source.setVisitReminder("1");
            sources.add(source);
        });
        boolean b = this.updateBatchById(sources);
        if (b) {
            return 1;
        } else {
            return 0;
        }

    }

    /**
     * 查询当天提醒患者就诊信息
     *
     * @return {@link List}<{@link GetPatientRemindersInfoTodayVo}>
     */
    @Override
    @DS("oracle_1")
    public List<GetPatientRemindersInfoTodayVo> getPatientTreatmentInfo() {
//        GetPatientRemindersInfoTodayVo build = GetPatientRemindersInfoTodayVo.builder().id("151212").idCard("758865199606081715").visitCardNo("No421").patientName("张三").diagnosisResult("诊断结果")
//                .drugsName("药物名称").Dosage("剂量").DrugsUseCycle("药物使用周期").build();
//        GetPatientRemindersInfoTodayVo build1 = GetPatientRemindersInfoTodayVo.builder().id("1512121").idCard("7588651996060817151").visitCardNo("No4211").patientName("张三1").diagnosisResult("诊断结果")
//                .drugsName("药物名称1").Dosage("剂量1").DrugsUseCycle("药物使用周期1").build();
//
//        List<GetPatientRemindersInfoTodayVo> list = new ArrayList<>();
//        for (int i = 0; i < 20; i++) {
//            list.add(GetPatientRemindersInfoTodayVo.builder().id("151212" + i).idCard("758865199606081715").visitCardNo("No421" + i).patientName("张三" + i).diagnosisResult("诊断结果")
//                    .drugsName("药物名称").Dosage("剂量").DrugsUseCycle("药物使用周期").build());
//        }
//
//        list.add(build);
//        list.add(build1);
//        return list;


        List<String> remindIdcardsToday = getRemindIdcardsToday();
        if (remindIdcardsToday == null || remindIdcardsToday.isEmpty()) {
            return null;
        }
        //当天提醒的就诊信息
        List<Jzxx> jzxxList = new ArrayList<>();


        for (String idcard : remindIdcardsToday) {
            LambdaQueryWrapper<Hzxx> hzxxlqw = Wrappers.lambdaQuery();
            hzxxlqw.eq(Hzxx::getIdCard, idcard);
            List<Hzxx> hzxxs = hzxxService.list(hzxxlqw);
            if (hzxxs.isEmpty()) {
                return null;
            }
            List<String> visitCardNos = hzxxs.stream().map(Hzxx::getVisitCardNo).distinct().collect(Collectors.toList());
            if (visitCardNos.isEmpty()) {
                return null;
            }
            for (String visitCardNo : visitCardNos) {
                LambdaQueryWrapper<Jzxx> jzxxlqw = Wrappers.lambdaQuery();
                jzxxlqw.eq(Jzxx::getVisitCardNo, visitCardNo);
                jzxxlqw.between(Jzxx::getJzsj, DateUtil.beginOfDay(DateUtil.date()), DateUtil.endOfDay(DateUtil.date()));
                List<Jzxx> jzxxs = jzxxService.list(jzxxlqw);
                jzxxList.addAll(jzxxs);
            }
        }
        List<GetPatientRemindersInfoTodayVo> list = BeanUtil.copyToList(jzxxList, GetPatientRemindersInfoTodayVo.class);
        return list;
    }


    /**
     * 获取当天需要提醒的身份证集合
     *
     * @return {@link List}<{@link String}>
     */
    @Override
    @DS("oracle_1")
    public List<String> getRemindIdcardsToday() {
        //查询当天就诊信息
        LambdaQueryWrapper<Jzxx> jzxxlqw = Wrappers.lambdaQuery();
        jzxxlqw.between(Jzxx::getJzsj, DateUtil.beginOfDay(DateUtil.date()), DateUtil.endOfDay(DateUtil.date()));
        List<Jzxx> jzxxs = jzxxService.list(jzxxlqw);
        if (jzxxs.isEmpty()) {
            return null;
        }
        List<String> visitCardNos = jzxxs.stream().map(Jzxx::getVisitCardNo).distinct().collect(Collectors.toList());
        if (visitCardNos.isEmpty()) {
            return null;
        }
        List<Hzxx> hzxxlist = new ArrayList<>();
        for (String visitCardNo : visitCardNos) {
            LambdaQueryWrapper<Hzxx> hzxxlqw = Wrappers.lambdaQuery();
            hzxxlqw.eq(Hzxx::getVisitCardNo, visitCardNo);
            List<Hzxx> hzxxs = hzxxService.list(hzxxlqw);
            if (hzxxs.isEmpty()) {
                return null;
            }
            hzxxlist.addAll(hzxxs);
        }

        //获得对应的身份证卡号（去重）
        List<String> idcards = hzxxlist.stream().map(Hzxx::getIdCard).distinct().collect(Collectors.toList());

        //获取提醒的样本源列表（身份证）
        List<Source> sources = sourceUtilService.getTXSources();
        if (sources.isEmpty()) {
            return null;
        }
        //获取提醒的身份证号（idcard）
        List<String> reminderIdCards = sources.stream().map(Source::getIdCard).distinct().collect(Collectors.toList());

        //需要提醒的身份证号
        List<String> remindIdcards = reminderIdCards.stream().filter(idcards::contains).collect(Collectors.toList());
        return remindIdcards;
    }

//    /**
//     * 获取提醒的样本源列表（身份证）
//     *
//     * @return {@link List}<{@link Source}>
//     */
//    public List<Source> getTXSources() {
//        DynamicDataSourceContextHolder.push("master");//手动切换
//        //设置提醒的样本源（身份证）
//        LambdaQueryWrapper<Source> sourcelqw = Wrappers.lambdaQuery();
//        sourcelqw.eq(Source::getVisitReminder, "1");
//        List<Source> sources = this.list(sourcelqw);
//        return sources;
//    }

    /**
     * 根据身份证号查询患者用药信息
     *
     * @param dto 身份证（带条件入参）
     * @return {@link List}<{@link GetPatientYYInfoByIdCardVo}>
     */
    @Override
    @DS("oracle_1")
    public List<GetPatientYYInfoByIdCardVo> getPatientYYInfoByIdCard(PatientTreatmentInfoDto dto) {
        LambdaQueryWrapper<Hzxx> hzxxlqw = Wrappers.lambdaQuery();
        hzxxlqw.eq(StringUtils.isNotBlank(dto.getVisitCardNo()), Hzxx::getVisitCardNo, dto.getVisitCardNo());
        hzxxlqw.eq(Hzxx::getIdCard, dto.getIdCard());
        List<Hzxx> hzxxs = hzxxService.list(hzxxlqw);
        if (hzxxs.isEmpty()) {
            return null;
        }
        List<String> visitCardNos = hzxxs.stream().map(Hzxx::getVisitCardNo).collect(Collectors.toList());
        if (visitCardNos.isEmpty()) {
            return null;
        }
        List<Yyxx> yyxxList = new ArrayList<>();
        for (String visitCardNo : visitCardNos) {
            LambdaQueryWrapper<Yyxx> yyxxlqw = Wrappers.lambdaQuery();
            yyxxlqw.eq(Yyxx::getVisitCardNo, visitCardNo);
            List<Yyxx> yyxxs = yyxxService.list(yyxxlqw);
            yyxxList.addAll(yyxxs);
        }

        List<GetPatientYYInfoByIdCardVo> list = BeanUtil.copyToList(yyxxList, GetPatientYYInfoByIdCardVo.class);
        return list;
//        List<GetPatientYYInfoByIdCardVo> list = new ArrayList<>();
//        for (int i = 0; i < 20; i++) {
//            list.add(GetPatientYYInfoByIdCardVo.builder().id("xxx"+i).visitCardNo("0110"+ i).drugsName("破伤风针"+i).Dosage("100ml单位"+i).DrugsUseCycle("1个周期"+i).build());
//        }
//        return list;
    }

    /**
     * 根据身份证号查询患者诊断信息
     *
     * @param dto 身份证（带条件入参）
     * @return {@link List}<{@link GetPatientZDInfoByIdCardVo}>
     */
    @Override
    @DS("oracle_1")
    public List<GetPatientZDInfoByIdCardVo> getPatientZDInfoByIdCard(PatientTreatmentInfoDto dto) {
        LambdaQueryWrapper<Hzxx> hzxxlqw = Wrappers.lambdaQuery();
        hzxxlqw.eq(StringUtils.isNotBlank(dto.getVisitCardNo()), Hzxx::getVisitCardNo, dto.getVisitCardNo());
        hzxxlqw.eq(Hzxx::getIdCard, dto.getIdCard());
        List<Hzxx> hzxxs = hzxxService.list(hzxxlqw);
        if (hzxxs.isEmpty()) {
            return null;
        }
        List<String> visitCardNos = hzxxs.stream().map(Hzxx::getVisitCardNo).collect(Collectors.toList());
        if (visitCardNos.isEmpty()) {
            return null;
        }
        List<Zdxx> zdxxList = new ArrayList<>();
        for (String visitCardNo : visitCardNos) {
            LambdaQueryWrapper<Zdxx> zdxxlqw = Wrappers.lambdaQuery();
            zdxxlqw.eq(Zdxx::getVisitCardNo, visitCardNo);
            List<Zdxx> zdxxs = zdxxService.list(zdxxlqw);
            if (!zdxxs.isEmpty()) {
                zdxxList.addAll(zdxxs);
            }

        }

        List<GetPatientZDInfoByIdCardVo> list = BeanUtil.copyToList(zdxxList, GetPatientZDInfoByIdCardVo.class);

        return list;
//        List<GetPatientZDInfoByIdCardVo> list = new ArrayList<>();
//        for (int i = 0; i < 20; i++) {
//            list.add(GetPatientZDInfoByIdCardVo.builder().id("xxx"+i).visitCardNo("0110"+ i).patientName("张三1"+i).diagnosisResult("诊断结果"+i).build());
//        }
//        return list;
    }

}
